package com.sikulifang.bank.simulation.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.db.Page;
import cn.hutool.db.PageResult;
import cn.hutool.db.sql.Direction;
import cn.hutool.db.sql.Order;
import cn.hutool.db.sql.SqlBuilder;
import com.sikulifang.bank.simulation.dto.QueryCriteriaDTO;
import com.sikulifang.bank.simulation.dto.SortDTO;
import com.sikulifang.bank.simulation.service.IBankMessage;
import com.sikulifang.bank.simulation.service.IService;
import com.sikulifang.bank.simulation.util.DataUtil;
import com.sikulifang.bank.simulation.util.R;
import com.sikulifang.common.db.properties.DbProperties;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.ArrayList;
import java.util.List;

/**
 * ClassName ServiceImpl
 * Description ServiceImpl
 *
 * @author Yat
 * Date 2023年6月9日, 0009 16:43
 * version 1.0
 */
@Slf4j
@Getter
public abstract class ServiceImpl implements IService {

    protected Db db;
    protected DbProperties dbProperties;
    protected List<IBankMessage> accountServices;

    @Override
    public List<String> getQueryCriteria() {
        return ListUtil.toList();
    }

    @Override
    @SneakyThrows
    public Entity get(Object id) {
        return db.get(Entity.create(getTableName()).set("id", id));
    }

    @Override
    @SneakyThrows
    public void delete(Object id) {
        db.del(Entity.create(getTableName()).set("id", id));
    }

    @Override
    @SneakyThrows
    public Entity list(QueryCriteriaDTO queryCriteria) {

        Page page = Page.of(queryCriteria.getPageNumber() - 1, queryCriteria.getPageSize());

        SqlBuilder builder = getSqlWrapper(queryCriteria);

        PageResult<Entity> pageResult = db.page(builder.build(), page);

        List<Dict> list = DataUtil.toCamelCase(pageResult);

        Entity response = new Entity();
        response.put(dbProperties.getRecords(), list);
        response.set(dbProperties.getPageNumber(), queryCriteria.getPageNumber());
        response.set(dbProperties.getPageSize(), pageResult.getPageSize());
        response.set(dbProperties.getTotalPage(), pageResult.getTotalPage());
        response.set(dbProperties.getTotalRecord(), pageResult.getTotal());
        return response;
    }

    @Override
    @SneakyThrows
    public Entity getDataByKey(Dict dict) {
        Entity where = Entity.create(getTableName());
        where.putAll(dict);
        return db.get(where);
    }

    @Override
    public R<String> saveUpdate(Entity entity) {
        Entity result = DataUtil.toUnderlineCase(entity);

        result.setTableName(getTableName());
        Integer id = result.getInt("id");
        result.remove("id");
        if (id == null) {
            return save(result);
        } else {
            return update(result, id);
        }
    }

    @SneakyThrows
    public R<String> save(Entity entity) {
        db.insert(entity);
        return R.ok();
    }

    @SneakyThrows
    public R<String> update(Entity entity, Object id) {
        db.update(entity, Entity.create().set("id", id));
        return R.ok();
    }

    protected SqlBuilder getSqlBuilder() {
        return SqlBuilder.create().select("*").from(getTableName()).where(" 1=1 ");
    }

    protected SqlBuilder getSqlWrapper(QueryCriteriaDTO queryCriteria) {
        String query = queryCriteria.getQuery();
        int count = 0;

        SqlBuilder builder = SqlBuilder.create().select("*").from(getTableName());
        if (StrUtil.isNotBlank(query)) {
            for (String queryCriterion : getQueryCriteria()) {
                String key = "where";
                if (count != 0) {
                    key = "or";
                }
                count++;
                builder.append(" " + key + " (" + queryCriterion + " like '%" + query + "%')");
            }
        }

        List<Order> orders = new ArrayList<>();

        List<SortDTO> dtoList = queryCriteria.getOrder();
        if (ArrayUtil.isNotEmpty(dtoList)) {
            for (SortDTO sortDTO : dtoList) {
                String field = sortDTO.getField();
                if (StrUtil.isNotBlank(field)) {
                    String sort = sortDTO.getSort();
                    Direction direction = Direction.ASC.name().equals(sort) ?
                            Direction.ASC : Direction.DESC;
                    Order order = new Order(field, direction);
                    orders.add(order);
                }
            }
        }

        builder.orderBy(orders.toArray(Order[]::new));
        return builder;
    }

    @Autowired
    public void setDb(Db db) {
        this.db = db;
    }

    @Autowired
    public void setDbProperties(DbProperties dbProperties) {
        this.dbProperties = dbProperties;
    }

    @Lazy
    @Autowired
    public void setAccountServices(List<IBankMessage> accountServices) {
        this.accountServices = accountServices;
    }
}
